gtk/main: Do not unset active state on button release w/o implicit grab
authorCarlos Garnacho <carlosg@gnome.org>
Thu, 19 Nov 2020 19:12:58 +0000 (20:12 +0100)
committerCarlos Garnacho <carlosg@gnome.org>
Thu, 19 Nov 2020 21:58:14 +0000 (22:58 +0100)
If an active grab gets undone on button press (e.g. closing a menu), we
will receive a button release on the new target even though it didn't handle
the button press, and disable ::active state.

This causes warnings when handling the button release, as it tries to undo
::active state that is not really there.

In order to fix this, check that the pointer focus actually had an implicit
grab at the time of receiving the button release, before trying to unset
the ::active state.

gtk/gtkmain.c

index 8b246477bea904f1c07079b2be7d54fb1949dccf..b9d12e19aa83ab714811215cc5097ab17fcb75ef 100644 (file)
@@ -1374,6 +1374,7 @@ handle_pointing_event (GdkEvent *event)
   double native_x, native_y;
   GtkWidget *native;
   GdkEventType type;
+  gboolean has_implicit;
 
   event_widget = gtk_get_event_widget (event);
   device = gdk_event_get_device (event);
@@ -1475,6 +1476,11 @@ handle_pointing_event (GdkEvent *event)
       target = gtk_window_lookup_effective_pointer_focus_widget (toplevel,
                                                                  device,
                                                                  sequence);
+      has_implicit =
+        gtk_window_lookup_pointer_focus_implicit_grab (toplevel,
+                                                       device,
+                                                       sequence) != NULL;
+
       gtk_window_set_pointer_focus_grab (toplevel, device, sequence,
                                          type == GDK_BUTTON_PRESS ?  target : NULL);
 
@@ -1491,7 +1497,10 @@ handle_pointing_event (GdkEvent *event)
           update_pointer_focus_state (toplevel, event, new_target);
         }
 
-      set_widget_active_state (target, type == GDK_BUTTON_RELEASE);
+      if (type == GDK_BUTTON_PRESS)
+        set_widget_active_state (target, FALSE);
+      else if (has_implicit)
+        set_widget_active_state (target, TRUE);
 
       break;
     case GDK_SCROLL: